import { IncomingMessage, ServerResponse } from "http";
import { Config, RequestWith, Store, User } from "./interface";
import { MD5 } from "./utils";
import { getSession } from './Session'
import * as path from 'path'
import { existsSync, readFileSync, writeFileSync } from "fs";

const avatar_store = (function () {
    const base_path = path.join(process.cwd(), '.avatar.json')
    let avatar_map = {}
    if (existsSync(base_path)) {
        avatar_map = JSON.parse(readFileSync(base_path).toString())
    }
    return {
        save (k: User['name'], v: string) {
            avatar_map[k] = v;
            writeFileSync(base_path, JSON.stringify(avatar_map, null, 2))
        },
        get (k: User['name']) {
            return avatar_map[k]
        }
    }
})()

export default (store: Store, cfg: Config) => {
    const changePassword = async (req: IncomingMessage, resp: ServerResponse) => {
        if (!req['post']) {
            return {
                error: 'POST only'
            }
        }
        const { pw0, pw1, pw2 } = req['post']
        const user: User = req['loginUser']
        let error: string | undefined
        if (user.password !== MD5(pw0)) {
            error = cfg.error_message?.wrong_old_pass
        } else if (!/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)\w{8,16}$/.test(pw1)) {
            error = cfg.error_message?.wrong_new_pass
        } else if (pw1 !== pw2) {
            error = cfg.error_message?.no_match_pass
        } else {
            try {
                await store.changeUserPassword?.(String(user.id), pw1)
            } catch (e) {
                error = e.toString()
            }
        }
        return error ? { error } : { success: true }
    }

    const loginUser = (req) => {
        const user = req.loginUser
        const session = getSession(user.token)
        return {
            ...user,
            password: '',
            token: session && session.session
        }
    }
    const token = (req) => {
        const user = req.loginUser
        return {
            token: user.token
        }
    }
    const user_list = async () => {
        const users = await store.users()
        return { users: users.filter(u => !u.isSys).map(u => {
            return {
                id: u.id,
                name: u.name,
                nickname: u.nickname,
                avatar: cfg.use_avatar && avatar_store.get(u.name) ? `/${cfg.admin_url}/avatar?username=${u.name}` : undefined,
            }
        }) }
    }

    const avatarUpdate = async (req: RequestWith) => {
        const user = req.loginUser
        avatar_store.save(user.name, req['body'].replace('avatar=', ''))
        return {
            success: true
        }
    }
    const avatar = (req: RequestWith, resp: ServerResponse) => {
        const username = req.data.username
        let imageBase64 = ''
        if (username) {
            imageBase64 = avatar_store.get(username) || imageBase64
        }
        const [_, base64] = imageBase64.substring(5).split(';base64,')
        return Buffer.from(base64, 'base64')
    }

    const allInfo = async () => {
        const authorities = await store.authorities()
        const roles = await store.roles()
        const users = await store.users()
        return {
            authorities,
            roles: roles,
            users: users.map(({password, ...other}) => other).filter((i) => !i.isSys)
        }
    }

    const addRole = async (req) => {
        if (req.post) {
            await store.addRole(req.post.name)
        }
        return {
            success: !!req.post
        }
    }
    const updateRoleAuthority = async (req) => {
        if (req.post) {
            const { roleId, authorityId, level } = req.post
            await store.updateRoleAuthority(roleId, authorityId, Number(level))
        }
        return {
            success: !!req.post
        }
    }
    const updateUserRole = async (req) => {
        if (req.post) {
            const { userId, roleId } = req.post
            await store.updateUserRole(userId, roleId)
        }
        return {
            success: !!req.post
        }
    }

    const addUser = async (req) => {
        if (req.post) {
            const { name, password, nickname } = req.post
            const result = await store.addUser(name, password, nickname)
            return result
        }
        return {
            success: !!req.post
        }
    }
    const delRole = async (req) => {
        if (req.post) {
            const { roleId } = req.post
            await store.delRole(roleId)
        }
        return {
            success: !!req.post
        }
    }
    const delUser = async (req) => {
        if (req.post) {
            const { userId } = req.post
            await store.delUser(userId)
        }
        return {
            success: !!req.post
        }
    }

    const resetPassword = async (req) => {
        if (req.post) {
            const { userId, password } = req.post
            await store.changeUserPassword?.(userId, password)
        }
        return {
            success: !!req.post
        }
    }

    const updateUserLockIPs = async (req) => {
        if (req.post && store.updateUserLockIPs) {
            const { userId, ips = '' } = req.post
            await store.updateUserLockIPs(userId, ips.split(/[,;\s]+/).filter(c => c))
            return {
                success: !!req.post
            }
        } else {
            return {
                error: 'error params'
            }
        }
    }
    const updateUserExpires = async (req) => {
        if (req.post && store.updateUserExpires) {
            const { userId, expires } = req.post
            if (expires) {
                await store.updateUserExpires(userId, Number(expires))
            }
            return {
                success: !!req.post
            }
        } else {
            return {
                error: 'error params'
            }
        }
    }
    
    return {
        changePassword,
        avatar,
        avatarUpdate,
        loginUser,
        token,
        user_list,
        allInfo,
        addRole,
        addUser,
        delRole,
        delUser,
        updateRoleAuthority,
        updateUserRole,
        resetPassword,
        updateUserLockIPs,
        updateUserExpires,
    }
}